/*
 * Copyright (c) 2015, the Dart project authors.
 *
 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package vm.element

// This file is generated by the script: pkg/vm_service/tool/generate.dart in dart-lang/sdk.

import com.google.gson.JsonArray
import com.google.gson.JsonObject

/**
 * {@link Instance} 表示 Dart 语言类 {@link Obj} 的一个实例。
 */
open class Instance(json: JsonObject) : InstanceRef(json) {


    /**
     * Map 实例的元素。
     *
     * 为以下实例类型提供：
     *  - Map
     *
     * 可以返回 <code>null</code>。
     */
    fun getAssociations(): ElementList<MapAssociation>? {
        val associations = json.get("associations") ?: return null

        return object : ElementList<MapAssociation>(associations.asJsonArray) {
            override fun basicGet(array: JsonArray, index: Int): MapAssociation {
                return MapAssociation(array.get(index).asJsonObject)
            }
        }
    }

    /**
     * TypeParameter 或 BoundedType 的边界。
     *
     * 该值将始终是以下类型之一：Type、TypeRef、TypeParameter、BoundedType。
     *
     * 为以下实例类型提供：
     *  - BoundedType
     *  - TypeParameter
     *
     * 可以返回 <code>null</code>。
     */
    fun getBound(): InstanceRef? {
        val obj = json.get("bound")?.asJsonObject ?: return null
        return InstanceRef(obj)
    }

    /**
     * TypedData 实例的字节。
     *
     * 数据以 Base64 编码字符串的形式提供。
     *
     * 为以下实例类型提供：
     *  - Uint8ClampedList
     *  - Uint8List
     *  - Uint16List
     *  - Uint32List
     *  - Uint64List
     *  - Int8List
     *  - Int16List
     *  - Int32List
     *  - Int64List
     *  - Float32List
     *  - Float64List
     *  - Int32x4List
     *  - Float32x4List
     *  - Float64x2List
     *
     * 可以返回 <code>null</code>。
     */
    fun getBytes(): String? {
        return getAsString("bytes")
    }

    /**
     * Instance references always include their class.
     */
    override fun getClassRef(): ClassRef {
        return ClassRef(json.get("class").asJsonObject)
    }

    /**
     * The context associated with a Closure instance.
     *
     * Provided for instance kinds:
     *  - Closure
     *
     * Can return <code>null</code>.
     */
    override fun getClosureContext(): ContextRef? {
        val obj = json.get("closureContext")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return ContextRef(obj)
    }

    /**
     * The function associated with a Closure instance.
     *
     * Provided for instance kinds:
     *  - Closure
     *
     * Can return <code>null</code>.
     */
    override fun getClosureFunction(): FuncRef? {
        val obj = json.get("closureFunction")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return FuncRef(obj)
    }

    /**
     * The number of elements or associations or codeunits returned. This is only provided when it is
     * less than length.
     *
     * Provided for instance kinds:
     *  - String
     *  - List
     *  - Map
     *  - Set
     *  - Uint8ClampedList
     *  - Uint8List
     *  - Uint16List
     *  - Uint32List
     *  - Uint64List
     *  - Int8List
     *  - Int16List
     *  - Int32List
     *  - Int64List
     *  - Float32List
     *  - Float64List
     *  - Int32x4List
     *  - Float32x4List
     *  - Float64x2List
     *
     * Can return <code>null</code>.
     */
    fun getCount(): Int {
        return getAsInt("count")
    }

    /**
     * A name associated with a ReceivePort used for debugging purposes.
     *
     * Provided for instance kinds:
     *  - ReceivePort
     *
     * Can return <code>null</code>.
     */
    override fun getDebugName(): String? {
        return getAsString("debugName")
    }

    /**
     * The elements of a List or Set instance.
     *
     * Provided for instance kinds:
     *  - List
     *  - Set
     *
     * @return one of <code>ElementList<InstanceRef></code> or <code>ElementList<Sentinel></code>
     *
     * Can return <code>null</code>.
     */
    fun getElements(): ElementList<InstanceRef>? {
        val elements = json.get("elements") ?: return null

        return object : ElementList<InstanceRef>(elements.asJsonArray) {
            override fun basicGet(array: JsonArray, index: Int): InstanceRef {
                return InstanceRef(array.get(index).asJsonObject)
            }
        }
    }

    /**
     * The (non-static) fields of this Instance.
     *
     * Provided for instance kinds:
     *  - PlainInstance
     *  - Record
     *
     * Can return <code>null</code>.
     */
    fun getFields(): ElementList<BoundField>? {
        val fields = json.get("fields") ?: return null

        return object : ElementList<BoundField>(fields.asJsonArray) {
            override fun basicGet(array: JsonArray, index: Int): BoundField {
                return BoundField(array.get(index).asJsonObject)
            }
        }
    }

    /**
     * The identityHashCode assigned to the allocated object. This hash code is the same as the hash
     * code provided in HeapSnapshot and CpuSample's returned by getAllocationTraces().
     */
    override fun getIdentityHashCode(): Int {
        return getAsInt("identityHashCode")
    }

    /**
     * Whether this regular expression is case sensitive.
     *
     * Provided for instance kinds:
     *  - RegExp
     *
     * Can return <code>null</code>.
     */
    fun getIsCaseSensitive(): Boolean {
        return getAsBoolean("isCaseSensitive")
    }

    /**
     * Whether this regular expression matches multiple lines.
     *
     * Provided for instance kinds:
     *  - RegExp
     *
     * Can return <code>null</code>.
     */
    fun getIsMultiLine(): Boolean {
        return getAsBoolean("isMultiLine")
    }

    /**
     * What kind of instance is this?
     */
    override fun getKind(): InstanceKind {
        val value = json.get("kind")
        try {
            return if (value == null) InstanceKind.Unknown else InstanceKind.valueOf(value.asString)
        } catch (e: IllegalArgumentException) {
            return InstanceKind.Unknown
        }
    }

    /**
     * The number of (non-static) fields of a PlainInstance, or the length of a List, or the number
     * of associations in a Map, or the number of codeunits in a String, or the total number of
     * fields (positional and named) in a Record.
     *
     * Provided for instance kinds:
     *  - PlainInstance
     *  - String
     *  - List
     *  - Map
     *  - Set
     *  - Uint8ClampedList
     *  - Uint8List
     *  - Uint16List
     *  - Uint32List
     *  - Uint64List
     *  - Int8List
     *  - Int16List
     *  - Int32List
     *  - Int64List
     *  - Float32List
     *  - Float64List
     *  - Int32x4List
     *  - Float32x4List
     *  - Float64x2List
     *  - Record
     *
     * Can return <code>null</code>.
     */
    override fun getLength(): Int {
        return getAsInt("length")
    }

    /**
     * The referent of a MirrorReference instance.
     *
     * Provided for instance kinds:
     *  - MirrorReference
     *
     * Can return <code>null</code>.
     */
    fun getMirrorReferent(): ObjRef? {
        val obj = json.get("mirrorReferent")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return ObjRef(obj)
    }


    /**
     * The index of the first element or association or codeunit returned. This is only provided when
     * it is non-zero.
     *
     * Provided for instance kinds:
     *  - String
     *  - List
     *  - Map
     *  - Set
     *  - Uint8ClampedList
     *  - Uint8List
     *  - Uint16List
     *  - Uint32List
     *  - Uint64List
     *  - Int8List
     *  - Int16List
     *  - Int32List
     *  - Int64List
     *  - Float32List
     *  - Float64List
     *  - Int32x4List
     *  - Float32x4List
     *  - Float64x2List
     *
     * Can return <code>null</code>.
     */
    fun getOffset(): Int {
        return getAsInt("offset")
    }

    /**
     * The index of a TypeParameter instance.
     *
     * Provided for instance kinds:
     *  - TypeParameter
     *
     * Can return <code>null</code>.
     */
    fun getParameterIndex(): Int {
        return getAsInt("parameterIndex")
    }

    /**
     * The parameterized class of a type parameter:
     *
     * Provided for instance kinds:
     *  - TypeParameter
     *
     * Can return <code>null</code>.
     */
    override fun getParameterizedClass(): ClassRef? {
        val obj = json.get("parameterizedClass")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return ClassRef(obj)
    }

    /**
     * The list of parameter types for a function.
     *
     * Provided for instance kinds:
     *  - FunctionType
     *
     * Can return <code>null</code>.
     */
    override fun getParameters(): ElementList<Parameter>? {
        val parameters = json.get("parameters") ?: return null

        return object : ElementList<Parameter>(parameters.asJsonArray) {
            override fun basicGet(array: JsonArray, index: Int): Parameter {
                return Parameter(array.get(index).asJsonObject)
            }
        }
    }

    /**
     * The pattern of a RegExp instance.
     *
     * Provided for instance kinds:
     *  - RegExp
     *
     * Can return <code>null</code>.
     */
    override fun getPattern(): InstanceRef? {
        val obj = json.get("pattern")?.asJsonObject ?: return null
        return InstanceRef(obj)
    }

    /**
     * The port ID for a ReceivePort.
     *
     * Provided for instance kinds:
     *  - ReceivePort
     *
     * Can return <code>null</code>.
     */
    override fun getPortId(): Int {
        return getAsInt("portId")
    }

    /**
     * The key for a WeakProperty instance.
     *
     * Provided for instance kinds:
     *  - WeakProperty
     *
     * Can return <code>null</code>.
     */
    fun getPropertyKey(): ObjRef? {
        val obj = json.get("propertyKey")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return ObjRef(obj)
    }

    /**
     * The key for a WeakProperty instance.
     *
     * Provided for instance kinds:
     *  - WeakProperty
     *
     * Can return <code>null</code>.
     */
    fun getPropertyValue(): ObjRef? {
        val obj = json.get("propertyValue")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return ObjRef(obj)
    }

    /**
     * The return type of a function.
     *
     * Provided for instance kinds:
     *  - FunctionType
     *
     * Can return <code>null</code>.
     */
    override fun getReturnType(): InstanceRef? {
        val obj = json.get("returnType")?.asJsonObject ?: return null
        return InstanceRef(obj)
    }

    /**
     * The target for a WeakReference instance.
     *
     * Provided for instance kinds:
     *  - WeakReference
     *
     * Can return <code>null</code>.
     */
    fun getTarget(): ObjRef? {
        val obj = json.get("target")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return ObjRef(obj)
    }

    /**
     * The type bounded by a BoundedType instance - or - the referent of a TypeRef instance.
     *
     * The value will always be of one of the kinds: Type, TypeRef, TypeParameter, BoundedType.
     *
     * Provided for instance kinds:
     *  - BoundedType
     *  - TypeRef
     *
     * Can return <code>null</code>.
     */
    fun getTargetType(): InstanceRef? {
        val obj = json.get("targetType")?.asJsonObject ?: return null
        return InstanceRef(obj)
    }

    /**
     * The type arguments for this type.
     *
     * Provided for instance kinds:
     *  - Type
     *
     * Can return <code>null</code>.
     */
    fun getTypeArguments(): TypeArgumentsRef? {
        val obj = json.get("typeArguments")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return TypeArgumentsRef(obj)
    }

    /**
     * The corresponding Class if this Type is canonical.
     *
     * Provided for instance kinds:
     *  - Type
     *
     * Can return <code>null</code>.
     */
    override fun getTypeClass(): ClassRef? {
        val obj = json.get("typeClass")?.asJsonObject ?: return null
        val type = json.get("type")?.asString
        if ("Instance" == type || "@Instance" == type) {
            val kind = json.get("kind")?.asString
            if ("Null" == kind) return null
        }
        return ClassRef(obj)
    }

    /**
     * The type parameters for a function.
     *
     * Provided for instance kinds:
     *  - FunctionType
     *
     * Can return <code>null</code>.
     */
    override fun getTypeParameters(): ElementList<InstanceRef>? {
        val typeParameters = json.get("typeParameters") ?: return null

        return object : ElementList<InstanceRef>(typeParameters.asJsonArray) {
            override fun basicGet(array: JsonArray, index: Int): InstanceRef {
                return InstanceRef(array.get(index).asJsonObject)
            }
        }
    }

    /**
     * The value of this instance as a string.
     *
     * Provided for the instance kinds:
     *  - Bool (true or false)
     *  - Double (suitable for passing to Double.parse())
     *  - Int (suitable for passing to int.parse())
     *  - String (value may be truncated)
     *  - StackTrace
     *
     * Can return <code>null</code>.
     */
    override fun getValueAsString(): String? {
        return getAsString("valueAsString")
    }

    /**
     * The valueAsString for String references may be truncated. If so, this property is added with
     * the value 'true'.
     *
     * New code should use 'length' and 'count' instead.
     *
     * Can return <code>null</code>.
     */
    override fun getValueAsStringIsTruncated(): Boolean {
        val elem = json.get("valueAsStringIsTruncated")
        return elem?.asBoolean ?: false
    }

    /**
     * Returns whether this instance represents null.
     */
    override fun isNull(): Boolean {
        return getKind() == InstanceKind.Null
    }

    override fun toString(): String {
        return "类型:${getKind()}, 值:${getValueAsString()}, 名称:${getName()}, DebugName:${getDebugName()}"
    }


    //获取枚举的值
    fun getEnumValueString(): String? {
        val type = getEnumType()
        val value = getEnumValue()
        if (type != null && value != null) {
            return "$type.$value"
        }
        return null
    }

    fun getEnumType(): String? {
        if (getKind() == InstanceKind.PlainInstance) {
            return getClassRef().getName()
        }
        return null
    }

    fun getEnumValue(): String? {
        if (getKind() == InstanceKind.PlainInstance) {
            val nameField = getFields()?.find { it.getName() == "_name" }
            if (nameField != null) {
                val enumValueString = nameField.getValue()?.getValueAsString()
                return enumValueString
            }
        }
        return null
    }
}
